<?php

namespace p5\objects;

class SessionUtils
{

    private static $use_full_uri = false;
    const PAGE_SESSION_SPACE_NAME = "_PAGE_SESSION_SPACE_NAME_";

    public static function get_global_session_matrix()
    {
        global $_SESSION;
        if (array_key_exists(self::getSessionKey(), $_SESSION)) {
            return unserialize($_SESSION[self::getSessionKey()]);
        }
        return array();
    }

    public static function persist_global_session_matrix($matrix)
    {
        global $_SESSION;
        $_SESSION[self::getSessionKey()] = serialize($matrix);
    }

    public static function request_to_session($name = "")
    {
        global $_REQUEST;
        if (empty($name)) {
            $name = array_keys($_REQUEST);
        }
        if (is_array($name)) {
            for ($i = 0; $i < count($name); $i++) {
                self::request_to_session($name[$i]);
            }
            return;
        } else {
            if (isset($_REQUEST[$name])) {
                self::set_session($name, RequestUtils::get($name));
            }
        }
    }

    public static function request_to_page_session($name)
    {
        global $_REQUEST;
        if (isset($_REQUEST[$name])) {
            self::set_page_session($name, RequestUtils::get($name));
        }
    }

    public static function get_session($name, $defaultValue = "")
    {
        $matrix = self::get_global_session_matrix();
        if (array_key_exists($name, $matrix)) {
            return $matrix[$name];
        }
        return $defaultValue;
    }

    public static function set_session($name, $object)
    {
        $matrix = self::get_global_session_matrix();
        $matrix[$name] = $object;
        self::persist_global_session_matrix($matrix);
    }

    public static function session_exists($name)
    {
        $defaultValue = "____aa____";
        return self::get_session($name, $defaultValue) != $defaultValue;
    }

    public static function remove_session($name)
    {
        $matrix = self::get_global_session_matrix();
        unset($matrix[$name]);
        self::persist_global_session_matrix($matrix);
    }

    public static function remove_all_session_parameters()
    {
        self::persist_global_session_matrix(array());
    }

    public static function removeAllExcept($names)
    {
        $names = is_string($names) ? explode(",", $names) : $names;
        $matrix = self::get_global_session_matrix();
        $keys = array_keys($matrix);
        foreach ($keys as $key) {
            if (in_array($key, $names)) {
                continue;
            }
            unset($matrix[$key]);
        }
        self::persist_global_session_matrix($matrix);
    }

    public static function use_full_uri()
    {
        self::$use_full_uri = true;
    }

    public static function get_page_parameter_session_key_name()
    {
        return self::get_page_session_key(self::$use_full_uri);
    }

    public static function get_page_session_key($use_full_uri = false)
    {
        global $_SERVER;

        $string = self::get(self::PAGE_SESSION_SPACE_NAME);
        if (!empty($string)) {
            return $string;
        }
        $page = self::firstServerValue(["ORIG_PATH_INFO", "SCRIPT_NAME"]);
        if ($use_full_uri) {
            self::firstServerValue(["REQUEST_URI", "REDIRECT_URL"]);
        }
        $key = str_replace("/", "_", $page) . ":_PAGE_SESSION_";
        $space = self::deep_get("session_space");
        if (!empty($space)) {
            $key .= ":$space";
        }
        return $key;
    }

    static public function firstServerValue($names)
    {
        global $_SERVER;
        foreach ($names as $name) {
            if (array_key_exists($name, $_SERVER)) {
                return $_SERVER[$name];
            }
        }
    }

    static public function set_page_session_space($name)
    {
        self::set(self::PAGE_SESSION_SPACE_NAME, $name);
    }

    static public function clear_page_session_space()
    {
        self::remove_session(self::PAGE_SESSION_SPACE_NAME);
    }

    public static function get_page_session_matrix()
    {
        $key = self::get_page_parameter_session_key_name();
        $matrix = self::get_global_session_matrix();
        if (array_key_exists($key, $matrix)) {
            return $matrix[$key];
        }
        $matrix = array();
        return $matrix;
    }

    public static function persist_page_session_matrix($matrix)
    {
        $key = self::get_page_parameter_session_key_name();
        $temp = self::get_global_session_matrix();
        $temp[$key] = $matrix;
        self::persist_global_session_matrix($temp);
    }

    public static function get_page_session($name, $defaultValue = "")
    {
        $matrix = self::get_page_session_matrix();
        if (array_key_exists($name, $matrix)) {
            return $matrix[$name];
        }
        return $defaultValue;
    }

    public static function get_session_parameters_with_prefix($prefix)
    {
        $matrix = self::get_global_session_matrix();
        return ArrayUtils::find_elements_with_key_prefix($matrix, $prefix);
    }

    public static function get_page_session_parameters_with_prefix($prefix)
    {
        $matrix = self::get_page_session_matrix();
        return ArrayUtils::find_elements_with_key_prefix($matrix, $prefix);
    }

    public static function set_page_session($name, $object)
    {
        $matrix = self::get_page_session_matrix();
        $matrix[$name] = $object;
        self::persist_page_session_matrix($matrix);
    }

    public static function remove_page_session($name)
    {
        $matrix = self::get_page_session_matrix();
        unset($matrix[$name]);
        self::persist_page_session_matrix($matrix);
    }

    public static function remove_page_session_by_prefix($prefix)
    {
        $matrix = self::get_page_session_matrix();
        $keys = array_keys($matrix);
        $len = strlen($prefix);
        foreach ($keys as $key) {
            if (strlen($key) >= $len) {
                if (substr($key, 0, $len) == $prefix) {
                    unset($matrix[$key]);
                }
            }
        }
        self::persist_page_session_matrix($matrix);
    }

    //情况页面所有参数缓存
    public static function clear_page_session()
    {
        $matrix = self::get_global_session_matrix();
        $key = self::get_page_session_key(false);
        if (array_key_exists($key, $matrix)) {
            unset($matrix[$key]);
        }
        $key = self::get_page_session_key(true);
        if (array_key_exists($key, $matrix)) {
            unset($matrix[$key]);
        }
        self::persist_global_session_matrix($matrix);
    }

    public static function get_session_parameters($list = array(), $isPageScope = true)
    {
        $matrix = array();
        for ($i = 0; $i < count($list); $i++) {
            $name = $list[$i];
            $value = self::deep_get($name, $isPageScope, "");
            if ($value != "") {
                $matrix[$name] = $value;
            }
        }
        return $matrix;
    }

    /**
     * 取走后马上从session中删除
     * @param $name
     * @param bool|false $isPageScope
     * @param string $defaultValue
     * @param string $type
     * @return string
     */
    public static function deepTake($name, $isPageScope = false, $defaultValue = "", $type = "string")
    {
        $value = self::deep_get($name, $isPageScope, $defaultValue, $type);
        if ($isPageScope) {
            self::remove_page_session($name);
        } else {
            self::remove($name);
        }
        return $value;
    }

    public static function deepGet($name, $isPageScope = false, $defaultValue = "", $type = "string")
    {
        return self::deep_get($name, $isPageScope, $defaultValue, $type);
    }

    public static function deep_get($name, $isPageScope = false, $defaultValue = "", $type = "string")
    {
        $name = str_replace("[]", "", $name);
        if ($isPageScope) {
            self::request_to_page_session($name);
            $value = self::get_page_session($name, $defaultValue);
        } else {
            self::request_to_session($name);
            $value = self::get_session($name, $defaultValue);
        }
        if ("int" == $type) {
            $value = is_int($value * 1) ? $value * 1 : $defaultValue;
        }
        return $value;
    }

    public static function search_parameters_to_page_session()
    {
        global $_REQUEST;
        $matrix = RequestUtils::get_parameters(array(), false);
        $keys = array_keys($matrix);
        foreach ($keys as $key) {
            if (strlen($key) > 7 && strtolower(substr($key, 0, 7)) == "search_") {
                self::request_to_page_session($key);
            }
        }
    }

    public static function all()
    {
        return self::get_global_session_matrix();
    }

    public static function getMagic($name, $defaultValue = "")
    {
        $index = strpos($name, ".");
        if ($index === false) {
            return static::get($name);
        }
        $matrix = explode(".", $name);
        $object = static::get($matrix[0]);
        if (empty($object)) {
            return $defaultValue;
        }
        return PropertyUtils::getMagic($object, substr($name, $index + 1), $defaultValue);
    }

    public static function get($name, $default_value = "")
    {
        return self::get_session($name, $default_value = "");
    }

    public static function set($name, $value)
    {
        self::set_session($name, $value);
    }

    public static function remove($name)
    {
        self::remove_session($name);
    }

    public static function increment_session($key, $size = 1)
    {
        $num = self::get_session($key, 0);
        $num += $size;
        self::set_session($key, $num);
        return $num;
    }

    public static function increment($key, $size = 1)
    {
        return self::increment_session($key, $size);
    }

    public static function getSuffixKey()
    {
        return str_replace('.', '_', $_SERVER['SERVER_NAME']);
    }

    public static function getSessionKey()
    {
        return "_SESSION_PARAMETERS_KEY_" . self::getSuffixKey();
    }

    public static function getSessionKeys()
    {
        $matrix = self::get_global_session_matrix();
        if (empty($matrix)) {
            return [];
        }
        return array_keys($matrix);
    }

    static public function setIfAbsent($name, $value)
    {
        if (self::session_exists($name)) {
            return;
        }
        self::set($name, $value);
    }

    static public function take($name)
    {
        $value = static::get($name);
        static::remove($name);
        return $value;
    }

}